package model

import (
	"encoding/json"
	"errors"
	"fmt"
	"math"
	"strconv"
	"strings"
	"time"

	"gddgame.cc/galaxy/common/dsl/game/user"
	"gddgame.cc/galaxy/utils"

	"gddgame.cc/galaxy/common/dsl/game/ad"
	"gddgame.cc/galaxy/common/dsl/game/ai"
	"gddgame.cc/galaxy/common/dsl/game/attr"
	"gddgame.cc/galaxy/common/dsl/game/badge"
	"gddgame.cc/galaxy/common/dsl/game/config"
	"gddgame.cc/galaxy/common/dsl/game/item"
	"gddgame.cc/galaxy/common/dsl/game/reward"
	target "gddgame.cc/galaxy/common/dsl/game/target"
	"gddgame.cc/galaxy/common/dsl/game/task"
)

//go:generate msgp

// Task - Inside
//msgp:tuple TaskInside
type TaskInside struct {
	Targets []int `json:"targets"`
	Objects []int `json:"objects"`
	Boss    int   `json:"boss"`
}

// Object - Extend
//msgp:tuple ObjectExtend
type ObjectExtend struct {
	Skill int   `json:"skill" msg:"skill"`
	Buffs []int `json:"buffs" msg:"buffs"`
}

// Badge - Inside
//msgp:tuple BadgeInside
type BadgeInside struct {
	// 扩展参数：玩家属性
	Attr      attr.AttrEffectSlice `json:"attr" sql:"JSON"`
	AttrEvent [][]attr.AttrEvent   `json:"attrEvent" sql:"JSON"`
}

// Item - Inside
//msgp:tuple ItemInside
type ItemInside struct {
	// 消耗道具：附带技能key
	Skill int `json:"skill" msg:"skill"`

	// 扩展参数：玩家属性
	Attr      attr.AttrEffectSlice `json:"attr" msg:"attr"`
	AttrEvent [][]attr.AttrEvent   `json:"attrEvent" msg:"attrEvent"`
}

const (
	// 战区类
	ZoneGame user.GameType = iota
	// 生存类
	SurvivalGame
	// 竞技类
	ContestGame
)

type GameMode int

const (
	_ GameMode = iota
	AnnihilateTaskMode
	DefendTaskMode
	ProtectTaskMode
)

var (
	ZoneModeList = []GameMode{AnnihilateTaskMode}
)

const (
	// 战区通关任务
	ZoneTask task.TaskType = iota
	// 战区附加任务
	ZoneAdditionTask
	// 每日任务
	DailyTask
	// 节日任务
	HolidayTask
)

const (
	// 武器
	WeaponItem item.ItemType = iota
	// 装甲
	MachineItem
	// 使用道具
	UseItem
)

const (
	GoldCoin item.CoinType = iota
	DiamondCoin
)

//msgp:tuple PlayerResult
type PlayerResult struct {
	// 统计信息
	Stats map[string]int `json:"stats" msg:"stats"`
	// 评分
	Level  int    `json:"level" msg:"level"`
	MVP    bool   `json:"mvp" msg:"mvp"`
	Entity string `json:"entity" msg:"entity"`
	// 获取的最大记录
	Max []string `json:"max" msg:"max"`
	// 加成
}

//msgp:tuple GameResult
type GameResult struct {
	// 获取的奖励
	Reward     *reward.Reward `json:"reward" msg:"reward"`
	TaskReward *reward.Reward `json:"task_reward" msg:"task_reward"`

	Players []*PlayerResult `json:"players" msg:"players"`
	Level   int             `json:"level" msg:"level"`
	Score   int             `json:"score" msg:"score"`
	//XP      int             `json:"xp" msg:"xp"`
	// 战斗时长
	Time    int  `json:"time" msg:"time"`
	Success bool `json:"success" msg:"success"`
}

const (
	StandBy ai.AiMode = iota
)

var (
	AiModeList = []int{StandBy: int(StandBy)}
)

//msgp:tuple RadarValue
type RadarValue struct {
	Index byte    `json:"index" msg:"index"`
	Value float32 `json:"value" msg:"value"`
}

type RadarValueSlice []RadarValue

func (slice RadarValueSlice) BindUser(source map[string]int32) []RadarValue {
	list := make([]float64, len(StatRadarList))
	sum := 0
	max := 0
	min := -1
	for index, key := range StatRadarList {
		value := int(source[key])
		list[index] = float64(value)
		sum += value
		if value > max {
			max = value
		}
		if value < min || min < 0 {
			min = value
		}
	}
	// 所有项的平均值+最大值最小值的平均值，指向2.5计算step
	step := float64(sum/len(StatRadarList)+(max+min)/2) / 2 / 2.5
	for index := range list {
		value := list[index] / step
		value, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", value), 32)
		slice = append(slice, RadarValue{Index: byte(index), Value: float32(math.Max(5, value))})
	}

	return slice
}

// 账号信息，等级信息，装备信息，道具信息，属性值
//msgp:tuple GameUser
type GameUser struct {
	UserId   string `json:"user_id" msg:"user_id"`
	ShowId   string `json:"id" msg:"id"`
	NickName string `json:"nick_name" msg:"nick_name"`
	Avatar   string `json:"avatar" msg:"avatar"`
	LastTime string `json:"last_time" msg:"last_time"`

	Score int `json:"score" msg:"score"`

	Gold    int `json:"gold" msg:"gold"`
	Diamond int `json:"diamond" msg:"diamond"`

	Entity string `json:"entity" msg:"entity"`

	Weapon  *UserItemExt `json:"weapon" msg:"weapon"`
	Machine *UserItemExt `json:"machine" msg:"machine"`

	Items  []*UserItemExt      `json:"items" msg:"items"`
	Badges []*badge.UserBadge  `json:"badges" msg:"badges"`
	Gifts  []reward.GiftNumber `json:"gifts" msg:"gifts"`

	BaseAttr  attr.AttrEffectSlice `json:"base_attr" msg:"base_attr"`
	BadgeAttr attr.AttrEffectSlice `json:"badge_attr" msg:"badge_attr"`
	ItemAttr  attr.AttrEffectSlice `json:"item_attr" msg:"item_attr"`

	StatRadar []float32 `json:"stat_radar" msg:"stat_radar"`
}

func (user *GameUser) BindGameUser(gameUser *user.GameUser) {
	user.UserId = gameUser.UserId
	user.ShowId = gameUser.ShowId
	user.NickName = gameUser.NickName
	user.Avatar = gameUser.Avatar

	user.LastTime = gameUser.LastTime
}

//msgp:tuple GameOtherUser
type GameOtherUser struct {
	UserId   string `json:"user_id" msg:"user_id"`
	ShowId   string `json:"id" msg:"id"`
	NickName string `json:"nick_name" msg:"nick_name"`
	Avatar   string `json:"avatar" msg:"avatar"`
	LastTime string `json:"last_time" msg:"last_time"`

	Score int `json:"score" msg:"score"`

	Entity string `json:"entity" msg:"entity"`

	Weapon  *UserItemExt `json:"weapon" msg:"weapon"`
	Machine *UserItemExt `json:"machine" msg:"machine"`

	Items []*UserItemExt `json:"items" msg:"items"`

	BaseAttr  attr.AttrEffectSlice `json:"base_attr" msg:"base_attr"`
	BadgeAttr attr.AttrEffectSlice `json:"badge_attr" msg:"badge_attr"`
	ItemAttr  attr.AttrEffectSlice `json:"item_attr" msg:"item_attr"`

	StatRadar []float32 `json:"stat_radar" msg:"stat_radar"`

	Online     bool `json:"online" msg:"online"`
	RoomStatus bool `json:"room_status" msg:"room_status"`
	TeamStatus bool `json:"team_status" msg:"team_status"`

	IsFriend bool `json:"is_friend" msg:"is_friend"`
}

func (user *GameOtherUser) BindGameUser(gameUser *user.GameOtherUser) {
	user.UserId = gameUser.UserId
	user.ShowId = gameUser.ShowId
	user.NickName = gameUser.NickName
	user.Avatar = gameUser.Avatar

	user.LastTime = gameUser.LastTime
	user.Online = gameUser.Online
	user.RoomStatus = gameUser.RoomStatus
	user.TeamStatus = gameUser.TeamStatus
	user.IsFriend = gameUser.IsFriend
}

//msgp:tuple BaseItem
type BaseItem struct {
	Id      int    `json:"id" msg:"id"`
	SkillId int    `json:"skill_id" msg:"skill_id"`
	Icon    string `json:"icon" msg:"icon"`
}

//msgp:tuple NumberItem
type NumberItem struct {
	Id        int    `json:"id" msg:"id"`
	SkillId   int    `json:"skill_id" msg:"skill_id"`
	Number    int    `json:"number" msg:"number"`
	IsConsume bool   `json:"is_consume" msg:"is_consume"`
	Icon      string `json:"icon" msg:"icon"`
}

//msgp:tuple GamePlayerExtend
type GamePlayerExtend struct {
	NickName string        `json:"nick_name" msg:"nick_name"`
	Avatar   string        `json:"avatar" msg:"avatar"`
	Weapon   *BaseItem     `json:"weapon" msg:"weapon"`
	Machine  *BaseItem     `json:"machine" msg:"machine"`
	Items    []*NumberItem `json:"items" msg:"items"`
	Buffs    []int         `json:"buff" msg:"buff"`
}

//msgp:tuple UserItemExt
type UserItemExt struct {
	Id         int `json:"id" msg:"id"`
	Number     int `json:"number" msg:"number"`
	Durability int `json:"durability" msg:"durability"`

	Item        *item.Item `json:"item" msg:"item"`
	RepairPrice int        `json:"repair_price" msg:"repair_price"`
}

func NewUserItem(userItem *UserItem, item *item.Item) *UserItemExt {
	ext := &UserItemExt{
		Id:          userItem.Id,
		Number:      userItem.Number,
		Durability:  userItem.Durability,
		Item:        item,
		RepairPrice: item.SellPrice * (100 - userItem.Durability) / 100,
	}
	return ext
}

const (
	_ user.MessageType = iota
	ShareMessage
)

var (
	MessageTemplates = map[user.MessageType]map[string]string{
		ShareMessage: {
			"zh": "{nick_name}加入，领取分享奖励",
			"en": "",
		},
	}
)

//msgp:tuple ZoneNodeExt
type ZoneNodeExt struct {
	Key     string `json:"key" msg:"key"`
	Name    string `json:"name" msg:"name"`
	Desc    string `json:"desc" msg:"desc"`
	Percent int    `json:"percent" msg:"percent"`
	Power   int    `json:"power" msg:"power"`

	NextTime int64 `json:"next_time" msg:"next_time"`

	MainTask     interface{} `json:"main_task" msg:"main_task"`
	AdditionTask interface{} `json:"addition_task" msg:"addition_task"`
	Level        int         `json:"level" msg:"level"`
	Mode         GameMode    `json:"mode" msg:"mode"`

	Boss   string `json:"boss" msg:"boss"`
	Target string `json:"target" msg:"target"`

	Status bool `json:"status" msg:"status"`

	updateTime *time.Time
}

func NewZoneNode(node *ZoneNode, mainTask *task.Task, additionTask *task.Task, nextTime *time.Time, targetMap map[int]*target.SettingTarget, language string) *ZoneNodeExt {
	ext := &ZoneNodeExt{
		Key:     node.Key,
		Name:    node.Name[language],
		Desc:    node.Desc[language],
		Percent: node.Percent,
		Power:   node.Power,

		NextTime:     nextTime.Unix(),
		MainTask:     mainTask,
		AdditionTask: additionTask,
		Level:        node.Level,

		Mode:   node.Mode,
		Status: node.Status,
	}
	boss := make([]string, len(node.Boss))
	for index, id := range node.Boss {
		// 设定显示大小
		boss[index] = targetMap[id].Entity + ":1"
	}
	ext.Boss = strings.Join(boss, "|")
	target := make([]string, len(node.Targets))
	for index, id := range node.Targets {
		target[index] = targetMap[id].Entity + ":1"
	}
	ext.Target = strings.Join(target, "|")
	if node.UpdateTime != nil {
		ext.updateTime = node.UpdateTime
	}
	return ext
}

func (node *ZoneNodeExt) HasUpdate(updateTime *time.Time) bool {
	if node.updateTime != nil {
		return node.updateTime.After(*updateTime)
	} else {
		return true
	}
}

const (
	// 宝箱抽奖
	GiftLevel1 reward.GiftType = "level1"
	GiftLevel2                 = "level2"
	GiftLevel3                 = "level3"
	GiftAd                     = "ad"
)

const (
	GiftAdPlane ad.AdPlane = iota
)

const (
	TeamStat      = "team"
	AdStat        = "ad"
	GiftStat      = "gift"
	MvpStat       = "mvp"
	PlaybookTimes = "playbookTimes"
	PlaybookTime  = "playbookTime"
	FullLevelStat = "fulllevel"
	MaxLogin      = "maxlogin"
	CurrentLogin  = "currentlogin"
	TaskStat      = "task"
	GoldStat      = "gold"
	DeadTimesStat = "deadTimes"
	DeadStat      = "dead"
	KillStat      = "kill"
)

type XPNumber int

var (
	// 经验值
	XPList = []XPNumber{
		100,
		300,
		500,
		1000,
		1500,
		2000,
		2500,
		3000,
		3500,
		4000,
		4500,
		5000,
		5500,
		6000,
		7000,
		8000,
		9000,
		10000,
		11000,
		13000,
		15000,
		17000,
		19000,
		21000,
		26000,
		31000,
		36000,
		41000,
		46000,
	}
)

type PointNumber int

var (
	PointList = []PointNumber{
		100,
		3000,
		5000,
		10000,
		15000,
		20000,
		25000,
		30000,
		35000,
		40000,
		45000,
		50000,
		55000,
		60000,
		65000,
	}
)

var (
	MaxPoint       PointNumber = 13000
	MaxWeekPoint               = 12000
	MaxReducePoint             = 2500
)

var (
	LevelObjectAttrs = [][]int{
		{900, 120, 80},
		{920, 121, 82},
		{940, 123, 83},
		{960, 124, 85},
		{980, 126, 86},
		{1000, 127, 88},
		{1020, 129, 89},
		{1040, 130, 91},
		{1060, 132, 92},
		{1080, 133, 94},
		{1100, 135, 95},
		{1020, 136, 97},
		{1040, 138, 98},
		{1060, 139, 100},
		{1080, 141, 101},
		{1100, 142, 103},
		{1120, 144, 104},
		{1140, 145, 106},
		{1160, 147, 107},
		{1180, 148, 109},
		{1200, 150, 110},
		{1220, 151, 112},
		{1240, 153, 113},
		{1260, 154, 115},
		{1280, 156, 116},
		{1300, 157, 118},
		{1320, 159, 119},
		{1340, 160, 121},
		{1360, 162, 122},
		{1380, 163, 124},
	}
	MaxObjectAttr = LevelObjectAttrs[len(LevelObjectAttrs)-1]
)

var (
	// 战力分布
	ZonePowerList = []int{
		600,
		700,
		900,
		1100,
		1300,
	}
)

var (
	// 战区节点限制
	NodeNumberLimit = []int{24, 12, 10, 8, 6, 4, 0}
	// 战区等级划分
	NodeLevelNumber    = []int{0, 100, 1000, 10000, 100000, 1000000}
	MaxPlaybookLevel   = 3
	MaxUserItemSet     = 4
	UserScoreBase      = 100
	DefaultBaseId      = 0
	DefaultEntity      = "Dwarf"
	DefaultShareReward = reward.Reward{
		Gold: 10,
	}
	DefaultItems = map[int]int{}
	TeamBuff     = 0
	LoginBadge   = 0
	GoldBadge    = 0
	AdBadge      = 0
	GiftBadge    = 0

	AdBrandList   = []string{"admob", "unity"}
	StatRadarList = []string{"survival", "skill", "fight", "call", "assist"}
)

var (
	GiftList     = []reward.GiftType{GiftLevel1, GiftLevel2, GiftLevel3}
	GiftAdGap    = 30
	GiftLogicMap = map[reward.GiftType]*reward.RewardLogic{
		GiftLevel1: {
			GoldMax:    100,
			GoldMin:    50,
			ItemNumber: 0,
			ConsumeMax: 4,
			ItemMax:    100,
			ItemMin:    0,
		},
	}
	// difficult  Random   GiftType
	RewardGiftLogic = [][]map[reward.GiftType]int{
		{ // 1
			{
				GiftLevel1: 1,
			}, {
				GiftLevel1: 1,
			}, {
				GiftLevel1: 2,
			},
		}, { // 2
			{
				GiftLevel1: 1,
			}, {
				GiftLevel1: 2,
			}, {
				GiftLevel2: 1,
			},
		}, { // 3
			{
				GiftLevel2: 1,
			}, {
				GiftLevel2: 1,
			}, {
				GiftLevel1: 1,
				GiftLevel2: 1,
			},
		}, { // 4
			{
				GiftLevel2: 1,
			}, {
				GiftLevel2: 1,
			}, {
				GiftLevel2: 2,
			},
		}, { // 5
			{
				GiftLevel3: 1,
			}, {
				GiftLevel3: 1,
			}, {
				GiftLevel3: 1,
				GiftLevel2: 1,
			},
		},
	}
)

func InitConfig(config *config.SettingConfig) (interface{}, error) {
	var err error
	switch config.Key {
	case "XpList":
		err = json.Unmarshal(utils.ToBytes(config.Value), &XPList)
		return XPList, err
	case "PointList":
		err = json.Unmarshal(utils.ToBytes(config.Value), &PointList)
		return PointList, err
	case "MaxPoint":
		MaxPoint = PointNumber(utils.ToInt(config.Value))
		return MaxPoint, nil
	case "MaxWeekPoint":
		MaxWeekPoint = utils.ToInt(config.Value)
		return MaxWeekPoint, nil
	case "MaxReducePoint":
		MaxReducePoint = utils.ToInt(config.Value)
		return MaxReducePoint, nil
	case "LevelObjectAttrs":
		err = json.Unmarshal(utils.ToBytes(config.Value), &LevelObjectAttrs)
		return LevelObjectAttrs, err
	case "MaxObjectAttr":
		err = json.Unmarshal(utils.ToBytes(config.Value), &MaxObjectAttr)
		return MaxObjectAttr, err
	case "ZonePowerList":
		err = json.Unmarshal(utils.ToBytes(config.Value), &ZonePowerList)
		return ZonePowerList, err
	case "NodeLevelNumber":
		err = json.Unmarshal(utils.ToBytes(config.Value), &NodeLevelNumber)
		return NodeLevelNumber, err
	case "NodeNumberLimit":
		err = json.Unmarshal(utils.ToBytes(config.Value), &NodeNumberLimit)
		return NodeNumberLimit, err
	case "GiftAdGap":
		GiftAdGap = utils.ToInt(config.Value)
		return GiftAdGap, nil
	case "UserScoreBase":
		UserScoreBase = utils.ToInt(config.Value)
		return UserScoreBase, nil
	case "DefaultBaseId":
		DefaultBaseId = utils.ToInt(config.Value)
		return DefaultBaseId, nil
	case "DefaultEntity":
		DefaultEntity = utils.ToString(config.Value)
		return DefaultEntity, nil
	case "DefaultItems":
		err = json.Unmarshal(utils.ToBytes(config.Value), &DefaultItems)
		return DefaultItems, err
	case "MessageTemplates":
		err = json.Unmarshal(utils.ToBytes(config.Value), &MessageTemplates)
		return MessageTemplates, err
	case "DefaultShareReward":
		err = json.Unmarshal(utils.ToBytes(config.Value), &DefaultShareReward)
		return DefaultShareReward, err
	case "GiftLogicMap":
		err = json.Unmarshal(utils.ToBytes(config.Value), &GiftLogicMap)
		return GiftLogicMap, err
	case "RewardGiftLogic":
		err = json.Unmarshal(utils.ToBytes(config.Value), &RewardGiftLogic)
		return RewardGiftLogic, err
	case "TeamBuff":
		TeamBuff = utils.ToInt(config.Value)
		return TeamBuff, nil
	case "LoginBadge":
		LoginBadge = utils.ToInt(config.Value)
		return LoginBadge, nil
	case "GoldBadge":
		GoldBadge = utils.ToInt(config.Value)
		return GoldBadge, nil
	case "AdBadge":
		AdBadge = utils.ToInt(config.Value)
		return AdBadge, nil
	case "GiftBadge":
		GiftBadge = utils.ToInt(config.Value)
		return GiftBadge, nil
	case "AdBrandList":
		err = json.Unmarshal(utils.ToBytes(config.Value), &AdBrandList)
		return AdBrandList, err
	case "StatRadarList":
		err = json.Unmarshal(utils.ToBytes(config.Value), &StatRadarList)
		return StatRadarList, err
	}
	return nil, errors.New("config " + config.Key + " is miss")
}
